/**
 * 
 */
package com.peak.spring.boot.core.web;

import java.util.List;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.PostMapping;

import com.google.common.collect.Lists;
import com.peak.spring.boot.api.entity.TreeEntity;
import com.peak.spring.boot.api.repository.FilterParam;
import com.peak.spring.boot.api.service.TreeService;
import com.peak.spring.boot.api.web.IdVo;
import com.peak.spring.boot.api.web.JsonList;
import com.peak.spring.boot.api.web.JsonMessage;
import com.peak.spring.boot.api.web.TreeVo;
import com.peak.spring.boot.builder.repository.FilterParamBuilder;
import com.peak.spring.boot.builder.web.JsonBuilder;
import com.peak.spring.boot.core.repository.JpaSorts;
import com.peak.spring.boot.tools.Converts;
import com.peak.spring.boot.tools.Emptys;

/**
 * @author Frank
 *
 */
public abstract class TreeController<T extends TreeEntity<T>, V extends IdVo> extends BaseController<T, V> {

	@Autowired
	protected TreeService treeService;

	@PostMapping("/tree/view")
	public List<TreeVo> treeView(HttpServletRequest request) {
		List<FilterParam> filterParams = FilterParamBuilder.create().parseRequest(request).build();
		List<T> trees = baseManager.findList(filterParams);
		return treeService.treeView(trees);
	}

	@PostMapping("/tree/grid")
	public JsonList treeGrid(HttpServletRequest request) {
		List<FilterParam> filterParams = FilterParamBuilder.create().parseRequest(request).build();
		List<T> trees = baseManager.findList(filterParams);
		trees = treeService.treeGrid(trees);
		return JsonBuilder.list().success().list(trees).convert(getVoClass()).build();
	}

	@PostMapping("/refreshLineNo")
	public JsonMessage refreshLineNo(HttpServletRequest request) {
		List<T> trees = baseManager.findAll(getSort());
		treeService.refreshLineNo(trees);
		return JsonBuilder.message().success().build();
	}

	protected Sort getSort() {
		return JpaSorts.orderBy("level_asc,sortNo_asc");
	}

	@Override
	protected T beforeSave(HttpServletRequest request, T entity) {
		String parentId = request.getParameter("parent_id");
		TreeEntity<T> oldParent = entity.getParent();
		boolean changeParent = false;
		// 设置父节点，比较复杂，存在修改的情况
		if (Emptys.isNotEmpty(parentId)) {
			if (oldParent == null || !oldParent.getId().equals(Converts.toByClass(parentId, oldParent.getId().getClass()))) {
				T newParent = baseManager.getOne(Converts.toLong(parentId));
				entity.setParent(newParent);
				entity.setLevel(newParent.getLevel() + 1);
				changeParent = true;
			}
		} else {
			if (oldParent != null) {
				entity.setParent(null);
				changeParent = true;
			}
			entity.setLevel(1);
		}
		// 修改子节点的等级
		if (changeParent && Emptys.isNotEmpty(entity.getId())) {
			List<Integer> ids = Lists.newArrayList();
			ids.add(entity.getId());
			updateLevel(ids, entity.getLevel());
		}
		// 默认给最大一个sortNo也给一个
		if (Emptys.isEmpty(entity.getId())) {
			int maxSort = getMaxSort(entity);
			entity.setSortNo(++maxSort);
		}
		return super.beforeSave(request, entity);
	}
	
	protected abstract int getMaxSort(T entity);

	private void updateLevel(List<Integer> parentIds, int parentLevel) {
		List<T> children = baseManager.findList(FilterParamBuilder.create()
				.in("parent.id", parentIds.stream().map(p -> Converts.toString(p)).collect(Collectors.joining(",")))
				.build());
		if (Emptys.isNotEmpty(children)) {
			List<Integer> ids = Lists.newArrayList();
			for (TreeEntity<T> child : children) {
				child.setLevel(parentLevel + 1);
				ids.add(child.getId());
			}
			baseManager.save(children);
			updateLevel(ids, parentLevel + 1);
		}
	}

	@Override
	protected JsonMessage afterSave(HttpServletRequest request, T entity) {
		List<T> trees = baseManager.findAll(getSort());
		treeService.refreshLineNo(trees);
		baseManager.save(trees);
		return super.afterSave(request, entity);
	}
}
